package com.futvan.z.framework.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;

import java.util.ResourceBundle;

import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import com.futvan.z.framework.common.bean.Code;
import com.futvan.z.framework.common.bean.Result;
import com.futvan.z.framework.core.z;
import com.futvan.z.system.zhttpservices.z_http_services;


/**
 * HTTP工具类
 * @author 4223947@qq.com
 *
 */
public class HttpUtil {
	public static void main(String[] args) {
	}

	/**
	 * Get请求
	 * @param url
	 * @param parameters
	 * @return
	 */
	public static String doGet(String url,Map<String,String> parameters){
		try {
			return get(url,parameters,null,0);
		} catch (Exception e) {
			z.Error("Error HTTP 请求", e);
			return "";
		}
	}

	/**
	 * Get请求
	 * @param url
	 * @param parameters
	 * @return
	 */
	public static String doGet(String url,Map<String,String> parameters,String ip,int port){
		try {
			return get(url,parameters,ip,port);
		} catch (Exception e) {
			z.Error("Error HTTP 请求", e);
			return "";
		}
	}

	/**
	 * Get请求
	 * @param url
	 * @param parameters
	 * @return
	 * @throws Exception 
	 */
	public static String doGetThrowsException(String url,Map<String,String> parameters,String ip,int port) throws Exception{
		return get(url,parameters,ip,port);
	}

	/**
	 * Post请求
	 * @param url
	 * @param parameters
	 * @return
	 */
	public static String doPost(String url,Map<String,String> parameters){
		try {
			return post(url,parameters,null,0);
		} catch (Exception e) {
			z.Error("Error HTTP 请求", e);
			return "";
		}
	}

	/**
	 * Post请求
	 * @param url
	 * @param parameters
	 * @return
	 */
	public static String doPost(String url,Map<String,String> parameters,String ip,int port){
		try {
			return post(url,parameters,ip,port);
		} catch (Exception e) {
			z.Error("Error HTTP 请求", e);
			return "";
		}
	}


	/**
	 * Post请求
	 * @param url
	 * @param parameters
	 * @return
	 * @throws Exception 
	 */
	public static String doPostThrowsException(String url,Map<String,String> parameters,String ip,int port) throws Exception{
		return post(url,parameters,ip,port);
	}

	/**
	 * Get请求
	 * @param url
	 * @param parameters
	 * @return
	 */
	public static Result doGetResult(String url,Map<String,String> parameters){
		String html;
		try {
			html = get(url,parameters,null,0);
			return JsonUtil.getObject(html, Result.class);
		} catch (Exception e) {
			Result er = new Result();
			er.setCode(Code.ERROR);
			er.setMsg("Error HTTP 请求");
			er.setData(e);
			return er;
		}

	}

	/**
	 * Get请求
	 * @param url
	 * @param parameters
	 * @return
	 */
	public static Result doGetResult(String url,Map<String,String> parameters,String ip,int port){
		try {
			String html = get(url,parameters,ip,port);
			return JsonUtil.getObject(html, Result.class);
		} catch (Exception e) {
			Result er = new Result();
			er.setCode(Code.ERROR);
			er.setMsg("Error HTTP 请求");
			er.setData(e);
			return er;
		}
	}

	/**
	 * Get请求
	 * @param url
	 * @param parameters
	 * @return
	 */
	public static Result doGetServices(z_http_services service,Map<String,String> parameters){
		Result result = new Result();
		if(z.isNotNull(parameters)) {
			parameters.put("is_oa_call", "true");
		}else {
			parameters = new HashMap<String,String>();
			parameters.put("is_oa_call", "true");
		}

		if(z.isNotNull(service)) {
			try {
				StringBuffer url = new StringBuffer();
				if("true".equals(z.sp.get("isSSL"))) {
					url.append("https://");
				}else {
					url.append("http://");
				}
				url.append(z.sp.get("serverip"));

				if("0".equals(service.getHttp_services_type())) {
					//SQL接口
					url.append("/httpservices");
					parameters.put("serviceid", service.getServiceid());

				}else if("1".equals(service.getHttp_services_type())) {
					//自定义程序接口
					url.append("/"+service.getServiceid());
				}

				String html = get(url.toString(),parameters,null,0);
				result = JsonUtil.getObject(html, Result.class);
			} catch (Exception e) {
				result.setCode(Code.ERROR);
				result.setMsg("HTTP ERROR");
				result.setData(e);
			}
		}else {
			result.setCode(Code.ERROR);
			result.setMsg("service is null");
		}
		return result;
	}
	/**
	 * Post请求
	 * @param url
	 * @param parameters
	 * @return
	 */
	public static Result doPostResult(String url,Map<String,String> parameters){
		try {
			String html = post(url,parameters,null,0);
			return JsonUtil.getObject(html, Result.class);
		} catch (Exception e) {
			Result er = new Result();
			er.setCode(Code.ERROR);
			er.setMsg("Error HTTP 请求");
			er.setData(e);
			return er;
		}
	}

	/**
	 * Post请求
	 * @param url
	 * @param parameters
	 * @return
	 */
	public static Result doPostResult(String url,Map<String,String> parameters,String ip,int port){
		try {
			String html = post(url,parameters,ip,port);
			return JsonUtil.getObject(html, Result.class);
		} catch (Exception e) {
			Result er = new Result();
			er.setCode(Code.ERROR);
			er.setMsg("Error HTTP 请求");
			er.setData(e);
			return er;
		}
	}

	/**
	 * Post请求
	 * @param url
	 * @param parameters
	 * @return
	 */
	public static Result doPostServices(z_http_services service,Map<String,String> parameters){
		Result result = new Result();
		if(z.isNotNull(parameters)) {
			parameters.put("is_oa_call", "true");
		}else {
			parameters = new HashMap<String,String>();
			parameters.put("is_oa_call", "true");
		}

		if(z.isNotNull(service)) {
			try {
				StringBuffer url = new StringBuffer();
				if("true".equals(z.sp.get("isSSL"))) {
					url.append("https://");
				}else {
					url.append("http://");
				}
				url.append(z.sp.get("serverip"));

				if("0".equals(service.getHttp_services_type())) {
					//SQL接口
					url.append("/httpservices");
					parameters.put("serviceid", service.getServiceid());

				}else if("1".equals(service.getHttp_services_type())) {
					//自定义程序接口
					url.append("/"+service.getServiceid());
				}

				String html = post(url.toString(),parameters,null,0);
				result = JsonUtil.getObject(html, Result.class);
			} catch (Exception e) {
				result.setCode(Code.ERROR);
				result.setMsg("HTTP ERROR");
				result.setData(e);
			}
		}else {
			result.setCode(Code.ERROR);
			result.setMsg("service is null");
		}
		return result;
	}

	/**
	 * HTTP请求GET
	 * @param url
	 * @param parameters
	 * @return
	 */
	public static String get(String url,Map<String,String> parameters,String ip,int port)throws Exception{
		//		try {
		CloseableHttpClient httpclient = null;
		if(z.isNotNull(ip) && port>0) {
			HttpHost proxy = new HttpHost(ip, port, "http");
			RequestConfig defaultRequestConfig = RequestConfig.custom()
					.setConnectTimeout(5000)
					.setSocketTimeout(5000)
					.setConnectionRequestTimeout(5000)
					.setProxy(proxy)
					.build();

			//创建连接
			httpclient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig).build();
		}else {
			RequestConfig defaultRequestConfig = RequestConfig.custom()
					.setConnectTimeout(5000)
					.setSocketTimeout(5000)
					.setConnectionRequestTimeout(5000)
					.build();

			//创建连接
			httpclient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig).build();
		}

		//封闭参数
		URIBuilder builder = new URIBuilder(url);
		if(parameters!=null && parameters.size()>0) {
			for (Entry<String, String> entry : parameters.entrySet()) {
				builder.setParameter(entry.getKey(), entry.getValue());
			}
		}

		//创建请求
		HttpGet doGet = new HttpGet(builder.build());

		//User-Agent 为模拟chrome PC浏览器
		doGet.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)");
		doGet.addHeader("referrer", "no-referrer");

		//如果有代理IP。设置X-Forwarded-For为代理IP，隐藏真实IP
		if(z.isNotNull(ip)) {
			doGet.setHeader("X-Forwarded-For", ip);
		}

		//执行
		HttpResponse response = httpclient.execute(doGet);
		int status = response.getStatusLine().getStatusCode();
		if (status >= 200 && status < 300) {
			HttpEntity entity = response.getEntity();
			//如果返回信息不为空，直接输出。
			String html = entity != null ? EntityUtils.toString(entity,"utf-8"):"";
			return html;
		}else {
			z.Error("HTTP ERROR : " + status);
			return "";
		}
	}



	/**
	 * HTTP请求POST
	 * @param <T>
	 * @param url
	 * @param parameters
	 * @return
	 * @throws Exception 
	 * @throws ParseException 
	 */
	public static String post(String url,Map<String,String> parameters,String ip,int port) throws Exception{
		//		try {
		CloseableHttpClient httpclient = null;
		if(z.isNotNull(ip) && port>0) {
			HttpHost proxy = new HttpHost(ip, port, "http");
			RequestConfig defaultRequestConfig = RequestConfig.custom()
					.setConnectTimeout(5000)
					.setSocketTimeout(5000)
					.setConnectionRequestTimeout(5000)
					.setProxy(proxy)
					.build();

			//创建连接
			httpclient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig).build();
		}else {
			RequestConfig defaultRequestConfig = RequestConfig.custom()
					.setConnectTimeout(5000)
					.setSocketTimeout(5000)
					.setConnectionRequestTimeout(5000)
					.build();

			//创建连接
			httpclient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig).build();
		}

		//创建请求
		HttpPost doPost = new HttpPost(url);
		if(parameters!=null && parameters.size()>0) {
			List<NameValuePair> params = new ArrayList<NameValuePair>();
			for (Entry<String, String> entry : parameters.entrySet()) {
				params.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
			}
			doPost.setEntity(new UrlEncodedFormEntity(params,Consts.UTF_8));
		}
		

		//User-Agent 为模拟chrome PC浏览器
		doPost.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36");
		doPost.addHeader("referrer", "no-referrer");

		//如果有代理IP。设置X-Forwarded-For为代理IP，隐藏真实IP
		if(z.isNotNull(ip)) {
			doPost.setHeader("X-Forwarded-For", ip);
		}

		//执行
		HttpResponse response = httpclient.execute(doPost);
		int status = response.getStatusLine().getStatusCode();
		HttpEntity entity = response.getEntity();
		if (status >= 200 && status < 300) {
			String html = entity != null ? EntityUtils.toString(entity,"utf-8"):"";
			return html;
		}else {
			z.Error("HTTP出错:" + status+"|"+entity);
			return "";
		}
	}
	
	/**
	 * post form
	 * 
	 * @param host
	 * @param path
	 * @param method
	 * @param headers
	 * @param querys
	 * @param bodys
	 * @return
	 * @throws Exception
	 */
	public static String doPost2(String url,Map<String, String> headers,Map<String, String> querys, String body)throws Exception {  
		CloseableHttpClient httpClient = null;
		RequestConfig defaultRequestConfig = RequestConfig.custom()
				.setConnectTimeout(5000)
				.setSocketTimeout(5000)
				.setConnectionRequestTimeout(5000)
				.build();

		//创建连接
		httpClient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig).build();
//		HttpClient httpClient = new DefaultHttpClient();
		
		HttpPost request = new HttpPost(url);
        for (Map.Entry<String, String> e : headers.entrySet()) {
        	request.addHeader(e.getKey(), e.getValue());
        }

        if (body != null) {
        	request.setEntity(new StringEntity(body, "utf-8"));
        }

        HttpResponse response = httpClient.execute(request);
		int status = response.getStatusLine().getStatusCode();
		HttpEntity entity = response.getEntity();
		if (status >= 200 && status < 300) {
			String html = entity != null ? EntityUtils.toString(entity,"utf-8"):"";
			return html;
		}else {
			z.Error("HTTP出错:" + status+"|"+entity);
			return "";
		}
	}

	/**
	 * 下载文件{包括下载进度计算}
	 * @param url 文件地址
	 * @param path 保存路径(不包括文件名)
	 * @return
	 */
	public static Result download(String url,String path) {
		Result result = new Result();
		if(z.isNotNull(url)) {
			try {
				//创建连接
				RequestConfig defaultRequestConfig = RequestConfig.custom().setConnectTimeout(5000).setSocketTimeout(5000).setConnectionRequestTimeout(5000).build();
				CloseableHttpClient httpclient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig).build();
				//创建请求
				HttpGet doGet = new HttpGet(url);
				//User-Agent 为模拟chrome PC浏览器
				doGet.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36");
				doGet.addHeader("referrer", "no-referrer");

				//执行
				HttpResponse response = httpclient.execute(doGet);
				int status = response.getStatusLine().getStatusCode();
				if (status >= 200 && status < 300) {
					HttpEntity entity = response.getEntity();
					if(entity != null) {
						//如果路径为空，默认保存webapp目录中,文件名，先生成随机文件名，如果在返回信息的头文件中定义了文件名，就重新变更文件名
						String filename = z.newNumber();
						if(z.isNull(path)) {
							path = System.getProperty(z.sp.get("webAppRootKeyValue"))+"/temp/"+filename;
						}else {
							if("/".equals(path.substring(path.length()-1))) {
								path = path+filename;
							}else {
								path = path+"/"+filename;
							}
						}

						//获取扩展名
						Header ContentType = response.getEntity().getContentType();
						if (ContentType != null) {
							String[]v = ContentType.getValue().split("/");
							if(v.length>0 && z.isNotNull(v[1])) {
								path = path+"."+v[1];
							}
						}

						//获取文件长度
						BigDecimal fileLength = null;
						if(entity.getContentLength()>0) {
							fileLength = new BigDecimal(entity.getContentLength());
						}

						//创建连接
						InputStream is = entity.getContent();
						//创建输出流
						FileOutputStream fos = new FileOutputStream(path);
						int bytesRead = 0;
						BigDecimal bytesReadAll = new BigDecimal(0);
						int len = 10*1024;
						byte[] buffer = new byte[len];
						while((bytesRead = is.read(buffer,0,len))!=-1){
							//写入文件
							fos.write(buffer,0,bytesRead);
							//如果获取到文件长度。就显示下载进度
							if(z.isNotNull(fileLength)) {
								//计算下载进度
								bytesReadAll = bytesReadAll.add(new BigDecimal(bytesRead));
								BigDecimal jd = bytesReadAll.divide(fileLength,4,RoundingMode.CEILING);
								DecimalFormat df = new DecimalFormat("0.##%");
								//System.out.println("已下载："+df.format(jd));
							}
						}
						fos.close();
						is.close();
						result.setCode(Code.SUCCESS);
						result.setMsg("HTTP Download OK");
						result.setData(path);
					}else {
						result.setCode(Code.ERROR);
						result.setMsg("HTTP Download Error: 返回结果为空");
					}
				}else {
					result.setCode(Code.ERROR);
					result.setMsg("HTTP Download Error Status: " + status);
				}

			} catch (Exception e) {
				result.setCode(Code.ERROR);
				result.setMsg("HTTP Download Exception: "+StringUtil.ExceptionToString(e));
			}
		}else {
			result.setCode(Code.ERROR);
			result.setMsg("HTTP Download Error: URL is null");
		}

		return result;
	}

	/**
	 * 文件下载
	 * @param strUrl
	 * @param path
	 * @throws Exception
	 */
	public static String download(String strUrl,String path,String fileName) {
		String filename = "";
		try {
			String filepath = FileUtil.mkdirs(path);
			URL url = new URL(strUrl);
			//创建连接
			InputStream is = url.openStream();
			//生成输出流
			OutputStream os = new FileOutputStream(path+"/"+fileName);
			int bytesRead = 0;
			int len = 10*1024;
			byte[] buffer = new byte[len];
			while((bytesRead = is.read(buffer,0,len))!=-1){
				os.write(buffer,0,bytesRead);
			}
			os.close();
			is.close();
			filename = filepath+"\\"+fileName;
		} catch (FileNotFoundException fe) {
			filename = "下载文件不存在|"+strUrl;
		} catch(Exception e) {
			e.printStackTrace();
		}
		return filename;
	}

	/**
	 * 	测试代理IP是否可用
	 * @param ip
	 * @param prot
	 * @return
	 */
	public static boolean TestProxyIP(String ip,int port) {
		boolean result = false;
		if(z.isNotNull(ip) && port>0) {
			String r = doGet("https://www.baidu.com/", null,ip,port);
			if(z.isNotNull(r)) {
				result = true;
			}
		}
		return result;
	}


	/**
	 * 获取请求主机IP地址,如果通过代理进来，则透过防火墙获取真实IP地址;
	 * 
	 * @param request
	 * @return
	 * @throws IOException
	 */
	public final static String getIpAddress(HttpServletRequest request) throws IOException {
		// 获取请求主机IP地址,如果通过代理进来，则透过防火墙获取真实IP地址


		String ip = request.getHeader("X-Forwarded-For");
		z.Log("X-Forwarded-For - String ip=" + ip);

		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("Proxy-Client-IP");
				z.Log("Proxy-Client-IP - String ip=" + ip);
			}
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("WL-Proxy-Client-IP");
				z.Log("WL-Proxy-Client-IP - String ip=" + ip);
			}
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("HTTP_CLIENT_IP");
				z.Log("HTTP_CLIENT_IP - String ip=" + ip);
			}
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getHeader("HTTP_X_FORWARDED_FOR");
				z.Log("HTTP_X_FORWARDED_FOR - String ip=" + ip);
			}
			if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
				ip = request.getRemoteAddr();
				z.Log("getRemoteAddr - String ip=" + ip);
			}
		} else if (ip.length() > 15) {
			String[] ips = ip.split(",");
			for (int index = 0; index < ips.length; index++) {
				String strIp = (String) ips[index];
				if (!("unknown".equalsIgnoreCase(strIp))) {
					ip = strIp;
					break;
				}
			}
		}
		z.Log("来访真实IP地址 - String ip=" + ip);
		return ip;
	}
	/**
	 * HTTP Post 请求，发送json包体信息
	 * @param url
	 * @param json
	 * @return
	 * @throws Exception
	 */
	public static String doPostJson(String url,String json) throws Exception {
		RequestConfig defaultRequestConfig = RequestConfig.custom().setConnectTimeout(5000).setSocketTimeout(5000).setConnectionRequestTimeout(5000).build();
		//创建连接
		CloseableHttpClient httpclient = HttpClients.custom().setDefaultRequestConfig(defaultRequestConfig).build();
		//创建请求
		HttpPost doPost = new HttpPost(url);
		//User-Agent 为模拟chrome PC浏览器
		doPost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler 4.0)");
		doPost.addHeader("referrer", "no-referrer");
		StringEntity requestEntity = new StringEntity(json,"utf-8");
		requestEntity.setContentEncoding("UTF-8");    	        
		doPost.setHeader("Content-type", "application/json");
		doPost.setEntity(requestEntity);

		//执行
		HttpResponse response = httpclient.execute(doPost);
		int status = response.getStatusLine().getStatusCode();
		if (status >= 200 && status < 300) {
			HttpEntity entity = response.getEntity();
			//如果返回信息不为空，直接输出。
			String html = entity != null ? EntityUtils.toString(entity,"utf-8"):"";
			return html;
		}else {
			z.Error("HTTP ERROR : " + status);
			return "";
		}
	}
}
